﻿using LibGit2Sharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace CommonUtils
{
    public static class GitUtil
    {
        public static void Move(string folder, string src, string target)
        {
            ProcessUtil.RunAt(folder, "git", string.Format("mv {0} {1}", src.AddDoubleQuotes(), target.AddDoubleQuotes()));
        }

        public static bool HasDriver = !ProcessUtil.Run("git", "version").HasError;

        public static bool IsRepositoryRoot(string folder)
        {
            if (!HasDriver || FileBasic.IsFile(folder))
                return false;

            var markPath = folder.Combine(".git");

            return FileBasic.IsFolder(markPath) || FileBasic.IsFile(markPath);
        }

        public static ProcessExcuteInfo GetStatusInfo(string folder, bool judgeIsRepositoryRoot = false)
        {
            if (judgeIsRepositoryRoot && !IsRepositoryRoot(folder))
                return default;

            //影响原有git的图标获取 好像与争抢仓库的IO有关
            var startInfo = new ProcessStartInfo("git")
            {
                Arguments = "status",
                WorkingDirectory = folder
            };

            return ProcessUtil.Start(startInfo, 1.5);
        }

        public static GitStatus GetStatus(string folder, bool judgeIsRepositoryRoot = false)
        {
            var info = GetStatusInfo(folder, judgeIsRepositoryRoot);

            if (info == default)
                return GitStatus.NotGit;

            if (info.HasError)
                return GitStatus.Error;

            //NotGitKeywords
            if (info.Output.Contains("fatal: not a git repository (or any of the parent directories): .git"))
                return GitStatus.NotGit;

            //ConflictKeywords
            if (info.Output.Contains("(fix conflicts and run \"git commit\")"))
                return GitStatus.Conflict;

            //CommittedKeywords
            if (!info.Output.Contains("nothing to commit, working tree clean"))
                return GitStatus.Modified;

            //NotPushedKeywords
            if (info.Output.Contains("(use \"git push\" to publish your local commits)"))
                return GitStatus.Committed;

            return GitStatus.Pushed;
        }

        public static bool IsRepository(string folder)
        => HasDriver && (GetStatus(folder) != GitStatus.NotGit);

        public static ProcessExcuteInfo Pull(string folder, double exitSeconds = 0)
        {
            if (!IsRepositoryRoot(folder))
                return ProcessExcuteInfo.Default;
            var startInfo = new ProcessStartInfo("git");
            startInfo.Arguments = "pull";
            startInfo.WorkingDirectory = folder;
            return ProcessUtil.Start(startInfo, exitSeconds);
        }

        /// <summary>
        /// 子模块更新
        /// </summary>
        public static ProcessExcuteInfo SubmoduleUpdate(string folder, double exitSeconds = 0)
        {
            if (!IsRepositoryRoot(folder))
                return ProcessExcuteInfo.Default;
            var startInfo = new ProcessStartInfo("git");
            startInfo.Arguments = "submodule update --progress --init";
            startInfo.WorkingDirectory = folder;
            return ProcessUtil.Start(startInfo, exitSeconds);
        }

        /// <summary>
        /// 子模块同步
        /// </summary>
        public static ProcessExcuteInfo SubmoduleSync(string folder, double exitSeconds = 0)
        {
            if (!IsRepositoryRoot(folder))
                return ProcessExcuteInfo.Default;
            var startInfo = new ProcessStartInfo("git");
            startInfo.Arguments = "submodule sync";
            startInfo.WorkingDirectory = folder;
            return ProcessUtil.Start(startInfo, exitSeconds);
        }

        public static GitLog[] GetLogs(string folder, DateTime start, DateTime end, string author)
        {
            var startInfo = new ProcessStartInfo("git");
            startInfo.Arguments = "log" +
                " --after=" + start.Info().AddDoubleQuotes() +
                " --before=" + end.Info().AddDoubleQuotes() +
                " --author=" + author;
            startInfo.WorkingDirectory = folder;
            var excuteInfo = ProcessUtil.Start(startInfo);
            return GitLog.Analysis(excuteInfo.Output);
        }

        public static GitLog[] GetLogsByStep(string folder, DateTime start, DateTime end, string author)
        {
            var logs = new List<GitLog>();
            for (var step = start.AddDays(1); step < end; start = step, step = step.AddDays(1))
                logs.AddRange(GetLogs(folder, start, step, author));
            logs.AddRange(GetLogs(folder, start, end, author));
            return logs.OrderBy(m => m.DateTime).ToArray();
        }

        //todo dowith LibGit2Sharp
        //https://github.com/libgit2/libgit2sharp
        //https://github.com/libgit2/libgit2sharp/issues/1748
        public static GitStatus GetStatus1(string folder)
        {
            var repository = new Repository(folder);
            //检索状态
            var info = repository.RetrieveStatus(new StatusOptions());
            throw new NotImplementedException();
        }

        public static bool HasUpdate(string folder)
        {
            var repository = new Repository(folder);
            //检索状态
            var info = repository.RetrieveStatus(new StatusOptions());
            throw new NotImplementedException();
        }
    }
}
